<?php

declare(strict_types=1);

namespace App\Utils\Other\Erp;
use App\Exception\InternalException;
use App\Utils\Http\Request;
use Hyperf\Collection\Arr;
use function Hyperf\Config\config;
use function Hyperf\Translation\__;

abstract Class Erp {

    /**
     * 接口名称
     * @var string
     */
    protected string $interfaces;

    /**
     * 配置
     * @var array
     */
    protected array $config;

    /**
     * 路径
     * @var string
     */
    protected string $url;

    /**
     * 类型
     * @var string
     */
    protected string $type;

    public function __construct(
        protected Request $request
    )
    {
        $this->config = config('cloud.erp');
    }

    /**
     * 操作
     * @param array $params
     * @return mixed
     */
    abstract public function handle(array $params);

    /**
     * 获取B2C请求参数
     * @param array $params
     * @return array
     */
    protected function params(array $params):array
    {
        $this->type = 'b2c';
        $this->url = "{$this->config[$this->type]['url']}{$this->config['edition']}/{$this->interfaces}";
        $params['app_key'] = $this->config[$this->type]['app_key'];
        $params['format'] = 'json';
        $params['timestamp'] = getMillisecond(true);
        $params['sign'] = $this->sign($params);

        return $params;
    }

    /**
     * 获取签名
     * @param array $params
     * @return string
     */
    protected function sign(array $params):string
    {
        ksort($params);
        $str = '';
        foreach ($params as $key => $param) {
            $str .= "{$key}{$param}";
        }

        $secret = $this->config[$this->type]['app_secret'];
        return strtoupper(md5("{$secret}$str{$secret}"));
    }

    /**
     * 获取API请求参数
     * @param array $params
     * @return array
     */
    protected function apiParams(array $params):array
    {
        $this->type = 'api';
        $this->url = "{$this->config[$this->type]['url']}{$this->interfaces}";
        $params['_app'] = $this->config[$this->type]['app_key'];
        $params['_t'] = time();
        $params['_s'] = '';
        $params['_sign'] = $this->_sign($params);

        return $params;
    }

    /**
     * 获取签名
     * @param array $params
     * @return string
     */
    protected function _sign(array $params): string
    {
        ksort($params);
        $strArr = [];
        foreach ($params as $key => $param) {
            $strArr[] = "{$key}=".urlencode($param);
        }
        $str = implode('&', $strArr);
        $encryption = $params['_sign_kind']??'md5';
        $secret = $this->config[$this->type]['app_secret'];
        return $encryption("{$secret}{$str}{$secret}");
    }

    /**
     * POST请求
     * @param $params
     * @return mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function post($params = [])
    {
        $response = $this->request->setHeaders(['Content-Type'=>'application/x-www-form-urlencoded;charset=utf-8'])
            ->post($this->url, $params);

        return $this->response($response);
    }

    /**
     * BODY
     * @param array $params
     * @return mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function body($params = [])
    {
        $response = $this->request->body($this->url, http_build_query($params));

        return $this->response($response);
    }

    /**
     * GET请求
     * @param array $params
     * @return mixed
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    protected function get(array $params=[])
    {
        $response = $this->request->get($this->url, $params);

        return $this->response($response);
    }

    /**
     * 响应
     * @param $response
     * @return mixed
     */
    protected function response($response)
    {
        $content = json_decode($response, true);
        if (!$content) {
            throw new InternalException(__('message.no_response_body'));
        } elseif ($this->type === 'api' && Arr::get($content, 'code')) {
            throw new InternalException("ERP ERROR: Code[{$content['code']}] Message[{$content['message']}]");
        } elseif ($this->type === 'b2c' && (!Arr::get($content, 'success') || Arr::get($content, 'error_code'))) {
            throw new InternalException('ERP ERROR: Code['.Arr::get($content, 'error_code', 1).'] Message['.Arr::get($content, 'error_msg', __('response.failed')).']');
        }

        return Arr::get($content, $this->type==='api'?'data':'response', []);
    }
}